#include "error.h"
#include "util.h"
#include <errno.h>

int Socket(int family, int type, int protocol)
{
    int n;
    if ((n = socket(family, type, protocol)) < 0)
    {
        err_sys("socket error");
    }
    return n;
}

void Connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
{
    if (connect(sockfd, servaddr, addrlen) < 0)
    {
        err_sys("connect error");
    }
//    return n;
}

void Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
    if (bind(sockfd, myaddr, addrlen) < 0)
    {
        err_sys("bind error");
    }
//    return n;
}

void Listen(int fd, int backlog)
{
    char *ptr;

    if ((ptr = getenv("LISTENQ")) != NULL)
    {
        backlog = atoi(ptr);
    }

    if (listen(fd, backlog) < 0)
    {
        err_sys("listen error");
    }
}

int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
{
    int n;
    if ((n = accept(sockfd, cliaddr, addrlen)) < 0)
    {
        err_sys("accept error");
    }
    return n;
}

void Close(int sockfd)
{
    if(close(sockfd) < 0)
    {
        err_sys("close error");
    }
}

ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t n, rc;
    char c, *ptr;

    ptr = (char *)vptr;
    for (n = 1; n < maxlen; n++)
    {
again:
        if ((rc = read(fd, &c, 1)) == 1)
        {
            *ptr++ = c;
            if (c == '\n')
                break;
        }
        else if(rc == 0)
        {
            *ptr = 0;
            return (n-1);
        }
        else
        {
            if (errno == EINTR)
                goto again;
            return -1;
        }
    }
    *ptr = 0;
    return n;
}

ssize_t Readn(int fd, void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nread;
    char *ptr;

    ptr = (char *)vptr;
    nleft = n;
    while (nleft > 0)
    {
        if ((nread = read(fd, ptr, nleft)) < 0)
        {
            if (errno == EINTR)
                nread = 0;
            else 
                return -1;
        }

        nleft -= nread;
        ptr += nread;
        if ((nread == 0) || (nread < nleft))
            break;
    }
    return n - nleft;
}

ssize_t Writen(int fd, const void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nwritten;
    const char *ptr;

    ptr = (char *)vptr;
    nleft = n;
    while(nleft > 0)
    {
        if ((nwritten = write(fd, ptr, nleft)) <= 0)
        {
            if (nwritten < 0 && errno == EINTR)
                nwritten = 0;
            else
                return -1;
        }
        nleft -= nwritten;
        ptr += nwritten;
    }
    return n;
}

void Inet_pton(int family, const char *strptr, void *addrptr)
{
    if (inet_pton(family, strptr, addrptr) < 0)
    {
        err_sys("inet_pton error");
    }
}

void Inet_ntop(int family, const void *addrptr, char *strptr, size_t len)
{
    if (inet_ntop(family, addrptr, strptr, len) == NULL)
    {
        err_sys("inet_ntop error");
    }
}


Sigfunc * Signal(int signo, Sigfunc *func)
{
    struct sigaction act, oact;

    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if (signo == SIGALRM)
    {
#ifdef SA_INTERRUPT
    act.sa_flags |= SA_INTERRUPT;
#endif
    }
    else
    {
#ifdef SA_RESTART
    act.sa_flags |= SA_RESTART;
#endif    
    }

    if (sigaction(signo, &act, &oact) < 0)
        return SIG_ERR;
    return oact.sa_handler;
}
